package controller;

import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Observable;

import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JToolBar;
import controller.DrawEventListener.modeOptions;
import model.ArrayQueue;
import model.ArrayStack;
import model.QueuePredict;
import model.StackPredict;

import view.DrawWindow;


public class ApplicationEventListener extends Observable implements ActionListener {
	
	private JToolBar toolBarStack;
	private StackPredict<String> stack;
	private QueuePredict<String> queue;
	private ArrayStack<String> arrayStack;
	private ArrayQueue<String> arrayQueue;
	private DrawWindow dw;
	private String status;
	
	public enum menuOptions {
		PUSH, POP, ADDPREDICT, REMOVEPREDICT, NEW_STACK, NEW_QUEUE, EXIT, ARRAYSTACK, ARRAYQUEUE, ABOUT
	}

	
	public ApplicationEventListener(JToolBar toolBarStack, DrawWindow dw) {
		this.toolBarStack = toolBarStack;
		this.dw = dw;
		startUp();
	}
	
	private void startUp(){
		
		//Displayed on startup and creates a new stack/queue based on choice.
		Object[] options = {"Stack", "Queue"};
		int n = JOptionPane.showOptionDialog(dw,"Choose the data type you wish to work with first!","New...",
											JOptionPane.YES_NO_CANCEL_OPTION,JOptionPane.QUESTION_MESSAGE,
											null,options,options[1]);   
		if(n==0){
			newStack();
		}
		if(n==1){
			newQueue();
		}
	}
	public void actionPerformed(ActionEvent e) {
		
		String cmd = e.getActionCommand();
		
		switch (menuOptions.valueOf(cmd)) {	
			case PUSH:
				if(status.equals("STACK")){	
				addStack();
				}
				if(status.equals("QUEUE")){
				addQueue();					
				}
				if(status.equals("ARRAYSTACK")){
				addArrayStack();
				}
				if(status.equals("ARRAYQUEUE")){
				addArrayQueue();	
				}
				break;
				
			case POP:
				if(status.equals("STACK")){
				removeStack();
				}
				if(status.equals("QUEUE")){
				removeQueue();	
				}
				if(status.equals("ARRAYSTACK")){
				removeArrayStack();	
				}
				if(status.equals("ARRAYQUEUE")){
				removeArrayQueue();	
				}
				break;
				
			case ADDPREDICT:
				if(status.equals("STACK")){
					addPredictStack();
				}
				
				if(status.equals("QUEUE")){
					addPredictQueue();
				}
				if(status.equals("ARRAYSTACK")){
					addPredictArrayStack();	
				}
				if(status.equals("ARRAYQUEUE")){
					addPredictArrayQueue();	
				}
				break;
				
			case REMOVEPREDICT:
				removePredict();
				break;			
				
			case NEW_STACK:
				newStack();
				break;		
				
			case NEW_QUEUE:
				newQueue();
				break;
				
			case EXIT:
				exit();
				break;	
				
			case ARRAYSTACK:
				newArrayStack();
				break;
				
			case ARRAYQUEUE:
				newArrayQueue();
				break;			
			case ABOUT:
				about();
				break;
			}			
	}
	
	
	private void addPredictArrayQueue() {
		String input = "";
		if(arrayQueue.size()<arrayQueue.getSize() && arrayQueue.size()>=1){
			input = JOptionPane.showInputDialog(dw, "Please Enter the value you would like added to the queue, then click on where, in the queue, you predict the element to be placed!");
			//Tells the AdapterQueue paint() method that the button has been pressed
			arrayQueue.setPressed(true);	
		
			dw.repaint();
		
			if(!input.isEmpty()){			
				dw.setInput(input);
			}		
			else{
				JOptionPane.showMessageDialog(dw,"No value was given, please enter a value before pressing Enter.");
			}
	
		dw.setPredictionMode(modeOptions.ADDPREDICT);	
		}

		else if(arrayQueue.size()==0){
			JOptionPane.showMessageDialog(dw,"There needs to be an existing element for add prediction to take place" );	
		}	
		else if(arrayQueue.size()==arrayQueue.getSize()){
			JOptionPane.showMessageDialog(dw,"Queue is Full, you need to remove elements before you can add more" );
		}
		
	}

	private void addPredictArrayStack() {
		String input = "";
		if(arrayStack.size()<arrayStack.getSize()  && arrayStack.size()>=1){
				input = JOptionPane.showInputDialog(dw, "Please Enter the value you would like added to the stack, then click on where, in the stack, you predict the element to be placed!");
				//Tells the AdapterStack paint() method that the button has been pressed
				arrayStack.setPressed(true);	
				dw.repaint();
				
				if(!input.isEmpty()){			
					dw.setInput(input);
				}		
				else{
					JOptionPane.showMessageDialog(dw,"No value was given, please enter a value before pressing Enter.");
				}
			
			dw.setPredictionMode(modeOptions.ADDPREDICT);	
		}
		
		else if(arrayStack.size()==0){
			JOptionPane.showMessageDialog(dw,"There needs to be an existing element for add prediction to take place" );	
		}	
		else if(arrayStack.size()==arrayStack.getSize()){
			JOptionPane.showMessageDialog(dw,"Stack is Full, you need to remove elements before you can add more" );
		}
		
	}

	private void newQueue(){
		status = "QUEUE";
		queue = new QueuePredict<String>();
		//clears the window and sends status message to drawWindow
		dw.clearWindow();
		dw.updateStatus(status);
	}
	
	private void newStack(){
		status = "STACK";
		stack = new StackPredict<String>();
		//clears the window and sends status message to drawWindow
		dw.clearWindow();
		dw.updateStatus(status);	
	}
	
	private void newArrayQueue(){
		status = "ARRAYQUEUE";
		boolean isNotNumber= true;
		
		arrayQueue = new ArrayQueue<String>();
		String input = JOptionPane.showInputDialog(dw, "Please Enter the size of the Array. Max Size = 8");
		if(!input.isEmpty()){
		//Tests to see if user has input a numeric value.
			char c[] = input.toCharArray();
			if(Character.isDigit(c[0])){
				isNotNumber = false;
				input = Character.toString(c[0]);
			}
	
			if(isNotNumber==false && Integer.parseInt(input)<=8){		
				arrayQueue.setSize(Integer.parseInt(input));
				dw.clearWindow();
				dw.updateStatus(status);
				dw.giveArrayQueue(arrayQueue);
			}
			else{
				JOptionPane.showMessageDialog(dw,"You need to enter a Numberic Value. Max Size = 8");
			}
		}
		else{
			JOptionPane.showMessageDialog(dw,"No value was given, please enter a value before pressing Enter." );
		}
		
	}
	
	private void newArrayStack(){
		status = "ARRAYSTACK";
		boolean isNotNumber= true;
		arrayStack = new ArrayStack<String>();
		String input = JOptionPane.showInputDialog(dw, "Please Enter the size of the Array. Max Size = 8");
		if(!input.isEmpty()){
			char c[] = input.toCharArray();
			if(Character.isDigit(c[0])){
				isNotNumber = false;
				input = Character.toString(c[0]);
			}
			
			if(isNotNumber==false && Integer.parseInt(input)<=8){
				arrayStack.setSize(Integer.parseInt(input));
				dw.clearWindow();
				dw.updateStatus(status);
				dw.giveArrayStack(arrayStack);
			}
			else{
				JOptionPane.showMessageDialog(dw,"You need to enter a Numberic Value. Max Size = 8");
			}
		}
		else{
			JOptionPane.showMessageDialog(dw,"No value was given, please enter a value before pressing Enter." );
		}
	}
	
	private void removeArrayQueue() {
		if(!arrayQueue.isEmpty()){
		String dequeue = "<html> The element <b> '" + arrayQueue.dequeue() + "'</b> was removed from the end of the queue</html>" ;
		//Formatting for clearly displaying removed element.
		JLabel label = new JLabel(dequeue);  
        label.setFont(new Font("serif", Font.PLAIN, 14));
		dw.repaint();
		JOptionPane.showMessageDialog(dw,label );

		}
		else{
			JOptionPane.showMessageDialog(dw,"The queue is empty, you need to add elements before any can be removed.");
		}	
		
	}


	private void addArrayQueue() {
		if(arrayQueue.size()<arrayQueue.getSize()){
			String input = JOptionPane.showInputDialog(dw, "Please Enter the value you would like added to the queue");
			if(!input.isEmpty()){
			//Limits the number of characters to one.
				arrayQueue.enqueue(input.substring(0,1));
				dw.giveQueue(queue);
				dw.repaint();
			}
			else{
				JOptionPane.showMessageDialog(dw,"No value was given, please enter a value before pressing Enter." );
			}		
		}	
		else{
			JOptionPane.showMessageDialog(dw,"Queue is Full, you need to remove elements before you can add more" );
			
		}		
	}


	private void removeArrayStack() {
		
		if(!arrayStack.isEmpty()){
		String poped = "<html> The element <b> '" + arrayStack.pop() + "'</b> was poped from the top of the stack</html>" ;
		//Formatting for clearly displaying removed element.
		JLabel label = new JLabel(poped);  
        label.setFont(new Font("serif", Font.PLAIN, 14));
		dw.repaint();
		JOptionPane.showMessageDialog(dw,label );
		}
		else{
			JOptionPane.showMessageDialog(dw,"The stack is empty, you need to add elements before any can be removed.");
		}
		
	}


	private void addArrayStack() {

			if(arrayStack.size()<arrayStack.getSize()){
				String input = JOptionPane.showInputDialog(dw, "Please Enter the value you would like added to the stack");
				if(!input.isEmpty()){
				//Limits the number of characters to one.
					arrayStack.push(input.substring(0,1));
					dw.giveArrayStack(arrayStack);
					dw.repaint();
				}
				else{
					JOptionPane.showMessageDialog(dw,"No value was given, please enter a value before pressing Enter." );
				}
			}
			else{
				JOptionPane.showMessageDialog(dw,"Stack is Full, you need to remove elements before you can add more" );
		}	
	}


	private void removeStack() {

		if(!stack.isEmpty()){
		String poped = "<html> The element <b> '" + stack.pop() + "'</b> was poped from the top of the stack</html>" ;
		//Formatting for clearly displaying removed element.
		JLabel label = new JLabel(poped);  
        label.setFont(new Font("serif", Font.PLAIN, 14));
		dw.repaint();
		JOptionPane.showMessageDialog(dw,label );
		}
		else{
			JOptionPane.showMessageDialog(dw,"The stack is empty, you need to add elements before any can be removed.");
		}
	}
	
	private void addPredictStack(){
		String input = "";
		if(stack.size()<8 && stack.size()>=1){
				input = JOptionPane.showInputDialog(dw, "Please Enter the value you would like added to the stack, then click on where, in the stack, you predict the element to be placed!");
				//Tells the AdapterStack paint() method that the button has been pressed
				stack.setPressed(true);	
				dw.repaint();
				
				if(!input.isEmpty()){			
					dw.setInput(input);
				}		
				else{
					JOptionPane.showMessageDialog(dw,"No value was given, please enter a value before pressing Enter.");
				}
			
			dw.setPredictionMode(modeOptions.ADDPREDICT);	
		}
		
		else if(stack.size()==0){
			JOptionPane.showMessageDialog(dw,"There needs to be an existing element for add prediction to take place" );	
		}	
		else if(stack.size()==8){
			JOptionPane.showMessageDialog(dw,"Stack is Full, you need to remove elements before you can add more" );
		}
	}
	
	private void addPredictQueue(){
		String input = "";
		if(queue.size()<8 && queue.size()>=1){
			input = JOptionPane.showInputDialog(dw, "Please Enter the value you would like added to the queue, then click on where, in the queue, you predict the element to be placed!");
			//Tells the AdapterQueue paint() method that the button has been pressed
			queue.setPressed(true);	
		
			dw.repaint();
		
			if(!input.isEmpty()){			
				dw.setInput(input);
			}		
			else{
				JOptionPane.showMessageDialog(dw,"No value was given, please enter a value before pressing Enter.");
			}
	
		dw.setPredictionMode(modeOptions.ADDPREDICT);	
		}

		else if(queue.size()==0){
			JOptionPane.showMessageDialog(dw,"There needs to be an existing element for add prediction to take place" );	
		}	
		else if(queue.size()==8){
			JOptionPane.showMessageDialog(dw,"Queue is Full, you need to remove elements before you can add more" );
		}
	}
		
	private void removePredict(){
		if(status.equals("STACK")){
			if(!stack.isEmpty()){
				JOptionPane.showMessageDialog(dw,"Please click on the element you predict will be removed!" );
				dw.setPredictionMode(modeOptions.REMOVEPREDICT);
			}
			else{
				JOptionPane.showMessageDialog(dw,"The stack is empty, you need to add elements before any can be removed.");
			}
		}
		
		if(status.equals("QUEUE")){
			if(!queue.isEmpty()){
				JOptionPane.showMessageDialog(dw,"Please click on the element you predict will be removed!" );
				dw.setPredictionMode(modeOptions.REMOVEPREDICT);
			}
			else{
				JOptionPane.showMessageDialog(dw,"The queue is empty, you need to add elements before any can be removed.");
			}
		}
		
		if(status.equals("ARRAYSTACK")){
			if(!arrayStack.isEmpty()){
				JOptionPane.showMessageDialog(dw,"Please click on the element you predict will be removed!" );
				dw.setPredictionMode(modeOptions.REMOVEPREDICT);
			}
			else{
				JOptionPane.showMessageDialog(dw,"The array stack is empty, you need to add elements before any can be removed.");
			}
		}
		
		if(status.equals("ARRAYQUEUE")){
			if(!arrayQueue.isEmpty()){
				JOptionPane.showMessageDialog(dw,"Please click on the element you predict will be removed!" );
				dw.setPredictionMode(modeOptions.REMOVEPREDICT);
			}
			else{
				JOptionPane.showMessageDialog(dw,"The array queue is empty, you need to add elements before any can be removed.");
			}
		}
	}
	
	
	private void removeQueue(){
		
		if(!queue.isEmpty()){
		String dequeue = "<html> The element <b> '" + queue.dequeue() + "'</b> was removed from the end of the queue</html>" ;
		//Formatting for clearly displaying removed element.
		JLabel label = new JLabel(dequeue);  
        label.setFont(new Font("serif", Font.PLAIN, 14));
		dw.repaint();
		JOptionPane.showMessageDialog(dw,label );

		}
		else{
			JOptionPane.showMessageDialog(dw,"The queue is empty, you need to add elements before any can be removed.");
		}		
	}


	private void exit(){
		System.exit(0);
	}
	
	private void about(){
		JOptionPane.showMessageDialog(dw, "Stack & QUeue Visualiser \n\n"
				+ "Creator: Sean Robertson \n"
				+ "Computer Science Final Project ");
	}
	
	private void addStack(){
		
			if(stack.size()<8){
				String input = JOptionPane.showInputDialog(dw, "Please Enter the value you would like added to the stack");
				if(!input.isEmpty()){
				//Limits the number of characters to one.
				stack.push(input.substring(0,1));
				dw.giveStack(stack);
				dw.repaint();
				}
				else{
					JOptionPane.showMessageDialog(dw,"No value was given, please enter a value before pressing Enter." );
				}
			}	
			else{
				JOptionPane.showMessageDialog(dw,"Stack is Full, you need to remove elements before you can add more" );
			}	
	}
	
	private void addQueue(){
		
		if(queue.size()<8){
				String input = JOptionPane.showInputDialog(dw, "Please Enter the value you would like added to the queue");
				if(!input.isEmpty()){
				//Limits the number of characters to one.
				queue.enqueue(input.substring(0,1));
				dw.giveQueue(queue);
				dw.repaint();
				}
				else{
					JOptionPane.showMessageDialog(dw,"No value was given, please enter a value before pressing Enter." );
				}		
			}	
			else{
				JOptionPane.showMessageDialog(dw,"Queue is Full, you need to remove elements before you can add more" );
			
		}
	}
	
}
